Trigger Script Programming Guide

Introduction

The Pharos Controllers offer many useful show control capabilities. Frequently it is the ability to cope with the particular show control needs of a project that is the critical factor in selecting a control system.

Show control broadly consists of two tasks. First we need to be able to interface with other devices, which may either be triggering us or be under our control. The Pharos Controller supports most of the core interfaces typically used for show control, either directly on the unit (contact closures, RS232, MIDI, TCP/UDP, time and date) or Remote Devices. Within the Triggers screen of the Designer software we can configure the Controller to detect particular triggers and how to respond to them.

Second we need to be able to make decisions. These could be simple choices between two alternatives - perhaps a contact closure needs to trigger a different timeline depending on whether it is during the day or during the night. Within the Triggers screen we support a range of conditions that can be used to quickly implement this sort of logical decision making. We also provide a facility to treat values received on an input as a variable that can be used to alter the behaviour of actions - such as using a number received via RS232 to select a particular timeline.

The standard capabilities offered in the Triggers screen are extensive, but a good show control system has the ability to cope with situations that are anything but standard. Within the Pharos system when things get non-standard then we can use scripting.

Lua is a simple programming language that allows users to extend the functionality of the Pharos system themselves. We use a freely available programming language called Lua. Anyone who has ever worked with a programming language will find all the typical tools are available, and it should be straightforward to pick up for those who have not. On top of the core Lua syntax we have added some dedicated Pharos functions that allow scripts to work directly with the capabilities of a Controller.

Not every problem requires script, but there are few show control problems that can't be solved using script where necessary. A few examples of situations where you might want to use script include:

We will use some of the situations as examples below.

The Basics

There are a few basic things you need to know straight away. If any of them are not immediately clear then don't worry - there are lots of examples of how to apply them in the following section.

Lua scripts are written as simple text files using any text editor. It is standard practice to use a .lua filename extension though this is not required. These text files can be loaded directly into the Script Editor within Designer.

Comments

It is good practice to include readable comments in your scripts so that you (or anyone else) will be able to easily tell what you were aiming to achieve. In Lua everything after two dashes on a line is treated as a comment.

-- This is a comment

This = is + not - a * comment -- but this is!

The whole point of comments is that they have no effect on the behaviour of the script. But I am introducing them first so that I can use them within the examples that follow.

Variables

If you want to store a piece of data - whether it is a number (referred to as an integer, float or real), some text (referred to as a string) or just true or false (refer to as a boolean)- then you use a variable. You create a variable simply by giving it a name and using it in your script. A variable can store any type of data just by assigning it.

firstVariable = 10 -- assign a number

anotherVariable = "Some text" -- assign a string

When you next use these names then they will have the values that you assigned to them:

nextVariable = firstVariable + 5 -- value of nextVariable will be 15

Note that names are case-sensitive (i.e. capitals matter!), and once you have named a variable once then any time you use the same name you will be referring to the same variable - in programming terms it is global. This even applies across different scripts - so you can assign a number to a variable called bob in one script and then use the number in another script by referencing bob.

One of the most common errors when writing scripts is trying to use a named variable before it has been assigned a value - this will result in an error when the script is run. It is also very easy to use the same name in two different places and not realise that you are actually reusing a single variable. (There is a way of dealing with this for names you want to reuse that we will touch on later.)

Arithmetic

Scripts will often need to do some arithmetic - even if it is something very basic like keeping a counter of how many times it is run:

myCount = myCount + 1

All of the standard arithmetic operations are available. There is also a library of mathematical functions available should it be required, which includes things like random number generators.

Flow of Control

In most scripts there will be one or more points where you want to make choices. Lua provides four useful structures for this. The most common is if, where you can choose which path to take through the script by performing tests.

if myNumber < 5 then -- tests whether myNumber is less than 5

    -- first choice

elseif myNumber < 15 and myNumber > 10 then

    -- second choice

else

    -- third choice

end

The other control structures all involve blocks of script that need to be repeated a certain number of times. The most straightforward is the while loop, which will repeat the enclosed block of script as long as the test at the start is true:

myNumber = 10

while myNumber > 0 do

    -- some useful script

    myNumber = myNumber - 1 -- myNumber counts down

end

The repeat until loop is really exactly the same, but here the test is done at the end of each loop and it will repeat while the test is false.

myNumber = 1

maxNumber = 4096

repeat

    -- some useful script

    myNumber = myNumber * 2

until myNumber == maxNumber

Here it is worth noting the use of two equal signs == to mean 'is equal to' in a test. This is different from a single equal sign, which is used for assigning values. It is another very common mistake to assign a value when you meant to test if it was equal, and it can be hard to spot because it is valid syntax that will not generate an error. The opposite of == meaning 'is equal to' is ~= meaning 'is not equal to'.

The other control structure is the for loop, which has a number of powerful options beyond the scope of what we need here. But it is worth seeing how it can be used to do basic loops in a slightly neater way:

for i = 1,10 do

    -- some useful script where i has value 1 to 10

    -- i increments at the end of each loop			

end

A final word of caution regarding loops: be careful that you do not write a loop that will never exit! This is all too easy to do by forgetting to increment a counter value that you are using in the test for the loop. If your script has one of these 'infinite loops' then the Controller will get stuck when it runs the script and be reset by the watchdog feature (provided this is enabled). Make sure you test your scripts carefully before leaving them to run.

Tables

Often you will need to store a set of values within a script - these might be a list of timeline numbers or the current states of all the contact closure inputs. Lua allows us to store multiple values within a single named variable and this is called a Table.

A table has to be created before it can be used:

firstTable = {} -- creates an empty table

secondTable = { 5,3,9,7 } -- a table with 4 entries

You can then access entries within the table by indexing into it - signified by square brackets. The number within the square brackets identified which entry within the table you want to use or modify.

x = secondTable[3] -- x now equals 9 (3rd entry)

firstTable[1] = 5 -- entry 1 now has value 5

firstTable[7] = 3 -- entry 7 now has value 3

x = firstTable[1] + firstTable[7] -- x now equals 5 + 3

Note that we are allowed to assign values to entries within the table without doing anything special to change the size of the table. We can keep adding elements to the table as needed and Lua will take care of it for us. This makes it possible to write scripts using tables that will work regardless of how many entries there are in the table (e.g. a list of 4 timeline numbers or of 40).

Tables are particularly powerful when used together with the loops we looked at in the previous section. For example if I have a table of numbers and I wanted to find the smallest then I could use the following script:

numbers = { 71,93,22,45,16,33,84 }
smallest = numbers[1] -- initialise with the first value

i = 1 -- use to count loops

while numbers[i] do -- loop while numbers[i] exists

    if numbers[i] < smallest then

        smallest = numbers[i]

    end

    i = i+1

end

This is our first really functional piece of script and there are a couple of things worth noting.

Functions

Within script there are a whole range of pre-defined operations that you can call when writing your own scripts. Some of these are provided by the Lua language and are fully described in its documentation. Others have been provided by Pharos to allow you to interact with the Controller from script and are fully described in the manual. They are all called functions and accessed using a similar syntax. For example:

x = math.random(1,100)

This will assign variable x a value that is a random number between 1 and 100. The function math.random() is a standard function provided by Lua and we can control its behaviour by passing in an argument - in this case the values 1 and 100 to tell it the range within which we want our random number to fall.

t = 5

get_timeline(t):start()

get_timeline(num):start() is one of the functions provided by Pharos and it will start the timeline with the number passed in as an argument.

It is also possible to define your own functions as part of script. You might do this if there is a block of script that you know you will need to reuse in a lot of different places. It will be much easier to write the script in one place and then call it from wherever you need it.

function diff(a, b)

    if a > b then

        return a - b

    else

        return b - a

    end

end
v1 = 10

v2 = 6

v3 = diff(v1,v2) -- v3 == 4 

Note that the script containing the function definition must have been run before we try to call the function. It is often useful to have a script that is run by the Controller startup trigger which defines your functions and creates any tables - other scripts that are run by triggers can make use of those functions and tables.

More information

In this document we have only covered the basic concepts that are needed to understand or write useful scripts for the Controllers. For more extensive information on the Lua language there are two documents, both of which are available online at http://www.lua.org or can be bought as books from Amazon.

Related Topics Link IconRelated Topics